package net.j4love.nio.channels;

import org.junit.Assert;
import org.junit.Test;

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author he peng
 * @create 2018/6/1 18:43
 * @see
 */
public class AsyncFileChannelPerformanceTest {

    // 异步文件通道 、 同步文件通道 性能测试, 异步文件通道比同步的性能高 3 倍左右

    static final int LOOP = 1000000;

    @Test
    public void asyncReadTest() throws Exception {
        Path path = Paths.get("D:\\Documents\\Pictures\\test\\天净沙·秋思.txt");
        AsynchronousFileChannel fChannel = AsynchronousFileChannel.open(path , StandardOpenOption.READ);
        Assert.assertTrue(fChannel.isOpen());

        System.out.println("async file channel is open");

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(18, 20, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>());

        long sTime = System.currentTimeMillis();
        for (int i = 0 ; i < LOOP ; i++ ) {
            ByteBuffer buffer = ByteBuffer.allocate((int) fChannel.size());
            Future<Integer> future = fChannel.read(buffer, 0);

            threadPoolExecutor.execute(() -> {
                while (! future.isDone()) {
                    if (future.isCancelled()) {
                        break;
                    }
                }
                buffer.flip();
                byte[] bytes = new byte[buffer.remaining()];
                buffer.get(bytes);
            });
        }

        System.out.println("loop " + LOOP + " times async read file , cost time = " + (System.currentTimeMillis() - sTime) + " ms");
        fChannel.close();
//        Thread.sleep(100000);
        // loop 1000000 , time =
        // loop 3000000 , time =
    }

    @Test
    public void syncReadTest() throws Exception {
        Path path = Paths.get("D:\\Documents\\Pictures\\test\\天净沙·秋思.txt");
        FileChannel fChannel = FileChannel.open(path, StandardOpenOption.READ);
        Assert.assertTrue(fChannel.isOpen());

        System.out.println("async file channel is open");
        long sTime = System.currentTimeMillis();
        for (int i = 0 ; i < LOOP ; i++ ) {
            ByteBuffer buffer = ByteBuffer.allocate((int) fChannel.size());
            fChannel.read(buffer, 0);

            buffer.flip();
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
        }

        System.out.println("loop " + LOOP + " times sync read file , cost time = " + (System.currentTimeMillis() - sTime) + " ms");
        fChannel.close();

        // loop 1000000 , time =
        // loop 3000000 , time =
    }

    @Test
    public void asyncWriteTest() throws Exception {
        Path path = Paths.get("D:\\Documents\\Pictures\\test\\天净沙·秋思.txt");
        AsynchronousFileChannel fChannel = AsynchronousFileChannel.open(path , StandardOpenOption.CREATE , StandardOpenOption.WRITE);
        Assert.assertTrue(fChannel.isOpen());

        System.out.println("async file channel is open");

        String s = "天净沙·秋思\n" +
                "元代：马致远\n" +
                "枯藤老树昏鸦，\n" +
                "小桥流水人家，\n" +
                "古道西风瘦马。\n" +
                "夕阳西下，\n" +
                "断肠人在天涯。";
        byte[] bytes = s.getBytes(Charset.forName("utf-8"));
        ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
        buffer.put(bytes);
        buffer.flip();

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(18, 20, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>());

        long sTime = System.currentTimeMillis();
        for (int i = 0 ; i < LOOP ; i++ ) {
            ByteBuffer buffer1 = ByteBuffer.wrap(bytes);
            Future<Integer> future = fChannel.write(buffer1, 0);
            threadPoolExecutor.execute(() -> {
                while (! future.isDone()) {
                    if (future.isCancelled()) {
                        break;
                    }
                }
                buffer1.flip();
                byte[] bytes1 = new byte[buffer1.remaining()];
                buffer1.get(bytes1);
            });
        }

        System.out.println("loop " + LOOP + " times sync write file , cost time = " + (System.currentTimeMillis() - sTime) + " ms");
        fChannel.close();

        // loop 1000000 , time =
        // loop 3000000 , time =
    }

    @Test
    public void syncWriteTest() throws Exception {
        Path path = Paths.get("D:\\Documents\\Pictures\\test\\天净沙·秋思.txt");
        FileChannel fChannel = FileChannel.open(path, StandardOpenOption.CREATE,
                StandardOpenOption.WRITE , StandardOpenOption.APPEND);
        Assert.assertTrue(fChannel.isOpen());

        System.out.println("async file channel is open");

        String s = "天净沙·秋思\n" +
                "元代：马致远\n" +
                "枯藤老树昏鸦，\n" +
                "小桥流水人家，\n" +
                "古道西风瘦马。\n" +
                "夕阳西下，\n" +
                "断肠人在天涯。";
        byte[] bytes = s.getBytes(Charset.forName("utf-8"));
        ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
        buffer.put(bytes);
        buffer.flip();

        long sTime = System.currentTimeMillis();
        for (int i = 0 ; i < LOOP ; i++ ) {
            fChannel.write(buffer, 0);
            buffer.flip();
        }
        System.out.println("loop " + LOOP + " times sync write file , cost time = " + (System.currentTimeMillis() - sTime) + " ms");
        fChannel.close();

        // loop 1000000 , time = 127 ms , 119 ms , 126 ms , 117 ms , 139 ms , 116 ms , 130 ms , 119 ms , 114 ms
        // loop 3000000 , time = 317 ms , 320 ms , 305 ms , 321 ms , 347 ms , 323 ms , 313 ms , 315 ms , 309 ms
    }
}
